/*
 * FFplay : Simple Media Player based on the ffmpeg libraries
 * Copyright (c) 2003 Fabrice Bellard
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */
#define HAVE_AV_CONFIG_H
#include "avformat.h"

#include "cmdutils.h"
#include <string.h>
#include <sys/soundcard.h>
#include <sys/ioctl.h>
#include <sys/signal.h>
#include <unistd.h>
#include <linux/fb.h>
#include <fcntl.h>
#include <linux/version.h>
///#include <SDL.h>
#include <SDL_thread.h>
#include <SDL_timer.h>
#include <SDL_audio.h>
#include <sched.h>
#include <asm/param.h>

#include "libSDL/SDL_audiodev_c.h"

#ifdef CONFIG_WIN32
#undef main /* We don't want SDL to override our main() */
#endif

#if defined(__linux__)
//#define HAVE_X11
#endif

#ifdef HAVE_X11
#include <X11/Xlib.h>
#endif

/// must fit to framebuffer number of display driver
#define VIDEO_PICTURE_QUEUE_SIZE_MAX 20

#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,0))
#include "ffb-api.h"
#else
#define FLCD_GET_DATA_SEP   0x46db
#define FLCD_GET_DATA       0x46dc
#define FLCD_SET_FB_NUM     0x46dd
#define FLCD_SWITCH_MODE    0x46de
#define FLCD_CLOSE_PANEL    0x46df

struct flcd_data
{
    unsigned int buf_len;
    unsigned int uv_offset;
    unsigned int frame_no;
	unsigned int mp4_map_dma[VIDEO_PICTURE_QUEUE_SIZE_MAX];
};
#endif

//#define DEBUG_SYNC

#define MAX_VIDEOQ_SIZE (5 * 256 * 1024)
#if 0
#define MAX_AUDIOQ_SIZE (5 * 16 * 1024)
#else //reserve queue size
#define MAX_AUDIOQ_SIZE (2 * 16 * 1024)
#endif

/* SDL audio buffer size, in samples. Should be small to have precise
   A/V sync as SDL does not have hardware buffer fullness info. */
#define SDL_AUDIO_BUFFER_SIZE 1024

/* no AV sync correction is done if below the AV sync threshold */
#define AV_SYNC_THRESHOLD 0.08
/* no AV correction is done if too big error */
#define AV_NOSYNC_THRESHOLD 10.0

/* maximum audio speed change to get correct sync */
#define SAMPLE_CORRECTION_PERCENT_MAX 10

/* we use about AUDIO_DIFF_AVG_NB A-V differences to make the average */
#define AUDIO_DIFF_AVG_NB   20

/* NOTE: the size must be big enough to compensate the hardware audio buffersize size */
#define SAMPLE_ARRAY_SIZE (2*65536)


#define FLCD_MODE_RGB       0
#define FLCD_MODE_YCBCR     1

// christie
#define LCD 1
#define TVE 2

#define FFPLAY_SIG_MODE

typedef struct PacketQueue {
    AVPacketList *first_pkt, *last_pkt;
    int nb_packets;
    int size;
    int abort_request;
    SDL_mutex *mutex;
    SDL_cond *cond;
} PacketQueue;

/* Useful data types */
typedef struct SDL_Rect {
	Sint16 x, y;
	Uint16 w, h;
} SDL_Rect;

typedef struct VideoPicture {
    double pts; /* presentation time stamp for this picture */
	AVPicture pic;
    int width, height; /* source height & width */
} VideoPicture;

enum {
    AV_SYNC_AUDIO_MASTER, /* default choice */
    AV_SYNC_VIDEO_MASTER,
    AV_SYNC_EXTERNAL_CLOCK, /* synchronize to an external clock */
};

typedef struct VideoState {
    SDL_Thread *parse_tid;
    SDL_Thread *video_tid;
    AVInputFormat *iformat;
    int no_background;
    int abort_request;
    int paused;
    int last_paused;
    AVFormatContext *ic;
    int dtg_active_format;

    int audio_stream;
    
    int av_sync_type;
    double external_clock; /* external clock base */
    int64_t external_clock_time;

    double audio_clock;
    double audio_diff_cum; /* used for AV difference average computation */
    double audio_diff_avg_coef;
    double audio_diff_threshold;
    int audio_diff_avg_count;
    AVStream *audio_st;
    PacketQueue audioq;
    int audio_hw_buf_size;
    /* samples output by the codec. we reserve more space for avsync
       compensation */
    uint8_t audio_buf[(AVCODEC_MAX_AUDIO_FRAME_SIZE * 3) / 2]; 
    int audio_buf_size; /* in bytes */
    int audio_buf_index; /* in bytes */
    AVPacket audio_pkt;
    uint8_t *audio_pkt_data;
    int audio_pkt_size;
    int64_t audio_pkt_ipts;
    uint32_t audio_silence_len;
    
    int show_audio; /* if true, display audio samples */
    int16_t sample_array[SAMPLE_ARRAY_SIZE];
    int sample_array_index;
    int last_i_start;
    
    double frame_timer;
    double frame_last_pts;
    double frame_last_delay;
    double video_clock;
    int video_stream;
    AVStream *video_st;
    PacketQueue videoq;
    int64_t ipts;
    int picture_start; /* true if picture starts */
    double video_last_P_pts; /* pts of the last P picture (needed if B
                                frames are present) */
    double video_current_pts; /* current displayed pts (different from
                                 video_clock if frame fifos are used) */
    int64_t video_current_pts_time; /* time at which we updated
                                       video_current_pts - used to
                                       have running video pts */
    VideoPicture pictq[VIDEO_PICTURE_QUEUE_SIZE_MAX];
    int pictq_size, pictq_rindex, pictq_windex;
    int pictq_size_total;
	SDL_mutex *pictq_mutex;
    SDL_cond *pictq_cond;
    
    //    QETimer *video_timer;
    char filename[1024];
    int width, height, xleft, ytop;
    // ben added start
    int end_of_file;
	int pictq_frame_size;
} VideoState;
#define NO_DATA_IN_FILE		0x01
#define NO_PK_IN_VIDEOQ		0x02
#define NO_FRAME_IN_DSPQ	0x04
#define NO_PK_IN_AUDIOQ		0x08
void show_help(void);
static int audio_write_get_buf_size(VideoState *is);
static double get_master_clock(VideoState *is);

/* options specified by the user */
int fbfd = 0;		 // ben
struct fb_var_screeninfo vinfo;	 // ben
static AVInputFormat *file_iformat;
static AVImageFormat *image_format;
static const char *input_filename;
static int screen_width = 0;
static int screen_height = 0;
static int audio_disable;
static int video_disable;
static int display_disable;
static int show_status;
static int av_sync_type = AV_SYNC_AUDIO_MASTER;
static int display_dev = 0;
static unsigned int do_exit_check=0; //to prevent the data structure free before use it
static pid_t mainpid;
static int mjpeg_disable = 0;

/* current context */
//static int is_full_screen;
static VideoState *cur_stream;
static int64_t audio_callback_time;

#define FF_ALLOC_EVENT   (SDL_USEREVENT)
#define FF_REFRESH_EVENT (SDL_USEREVENT + 1)
#define FF_QUIT_EVENT    (SDL_USEREVENT + 2)

#ifdef ARRAY_NO_MALLOC
#include "pack.h"
#endif
/* packet queue handling */
static void packet_queue_init(PacketQueue *q)
{
    memset(q, 0, sizeof(PacketQueue));
    q->mutex = SDL_CreateMutex();
    q->cond = SDL_CreateCond();
}

static void packet_queue_end(PacketQueue *q)
{
    AVPacketList *pkt, *pkt1;

    for(pkt = q->first_pkt; pkt != NULL; pkt = pkt1) {
        pkt1 = pkt->next;
#ifdef ARRAY_NO_MALLOC
	 	if (pkt->pkt.stream_index == 0){
		  repv_put(&pkt->pkt);
		  pack_put(&video_pack);
		} else {
		  repa_put(&pkt->pkt);
		  pack_put(&audio_pack);
		}
#else
        av_free_packet(&pkt->pkt);
        av_free(pkt);
#endif
    }
    SDL_DestroyMutex(q->mutex);
    SDL_DestroyCond(q->cond);
}

static int packet_queue_put(PacketQueue *q, AVPacket *pkt)
{
    AVPacketList *pkt1;

#ifdef ARRAY_NO_MALLOC
	if (pkt->stream_index == 0) {
	  pkt1 = pack_get(&video_pack);
	}
	else {
	  pkt1 = pack_get(&audio_pack);
	}
#else
    pkt1 = av_malloc(sizeof(AVPacketList));
    if (!pkt1)
        return -1;
#endif
    pkt1->pkt = *pkt;
    pkt1->next = NULL;

    SDL_LockMutex(q->mutex);

    if (!q->last_pkt)
        q->first_pkt = pkt1;
    else
        q->last_pkt->next = pkt1;
    q->last_pkt = pkt1;
    q->nb_packets++;
    q->size += pkt1->pkt.size;
    /* XXX: should duplicate packet data in DV case */
    SDL_CondSignal(q->cond);
    SDL_UnlockMutex(q->mutex);
    return 0;
}

static void packet_queue_abort(PacketQueue *q)
{
    SDL_LockMutex(q->mutex);

    q->abort_request = 1;
    
    SDL_CondSignal(q->cond);

    SDL_UnlockMutex(q->mutex);
}

/* return < 0 if aborted, 0 if no packet and > 0 if packet.  */
static int packet_queue_get(PacketQueue *q, AVPacket *pkt, int block)
{
    AVPacketList *pkt1;
    int ret;

    SDL_LockMutex(q->mutex);

    for(;;) {
        if (q->abort_request) {
            ret = -1;
            break;
        }
            
        pkt1 = q->first_pkt;
        if (pkt1) {
            q->first_pkt = pkt1->next;
            if (!q->first_pkt)
                q->last_pkt = NULL;
            q->nb_packets--;
            q->size -= pkt1->pkt.size;
            *pkt = pkt1->pkt;
#ifdef ARRAY_NO_MALLOC
	   		if (pkt->stream_index == 0)
			  pack_put(&video_pack);
			else
			  pack_put(&audio_pack);
#else
            av_free(pkt1);
#endif
            ret = 1;
            break;
        } else if (!block) {
            ret = 0;
            break;
        } else {
            SDL_CondWait(q->cond, q->mutex);
        }
    }
    SDL_UnlockMutex(q->mutex);
    return ret;
}

/* return < 0 if aborted, 0 if no packet and > 0 if packet.  */
static int packet_queue_get_block(PacketQueue *q, AVPacket *pkt, int end_of_file)
{
    AVPacketList *pkt1;
    int ret;

    SDL_LockMutex(q->mutex);

    for(;;) {
        if (q->abort_request) {
            ret = -1;
            break;
        }
            
        pkt1 = q->first_pkt;
        if (pkt1) {
            q->first_pkt = pkt1->next;
            if (!q->first_pkt)
                q->last_pkt = NULL;
            q->nb_packets--;
            q->size -= pkt1->pkt.size;
            *pkt = pkt1->pkt;
#ifdef ARRAY_NO_MALLOC
	   		if (pkt->stream_index == 0)
			  pack_put(&video_pack);
			else
			  pack_put(&audio_pack);
#else
            av_free(pkt1);
#endif
            ret = 1;
            break;
        } else {
			if (end_of_file & NO_DATA_IN_FILE) {
				ret = -1;
				break;
			}
			else
				SDL_CondWait(q->cond, q->mutex);
        }
    }
    SDL_UnlockMutex(q->mutex);
    return ret;
}

unsigned int start_queuing=0;
VideoState *sig_is=0;
double sig_actual_delay=0;
unsigned int fbq_wait=0,chkconnect=0,skip_frame=0;
static void sig_user(void)
{
}
static void sig_show(void)
{
    int fbn=0; //init to 0
    VideoPicture *vp;
    double tmp;

    if(sig_is==0){
	if( !mjpeg_disable ) {  // haking for static jpeg
	    printf("null is\n");fflush(stdout);
	    ioctl(fbfd,FLCD_SET_FB_NUM,&fbn);
	}
        goto end;
    }
    if(do_exit_check)
    {
        //printf("exit now\n");fflush(stdout);
        ioctl(fbfd,FLCD_SET_FB_NUM,&fbn);
        goto end;
    }
    if(sig_is->pictq_size<2)
    {
        //printf("<1>Computing Power Not Enough!\n");fflush(stdout);
	SDL_LockMutex(sig_is->pictq_mutex);
        goto send_sig;
    }

    if (sig_actual_delay>0.1){
#if defined(DEBUG_SYNC)
	    printf("A/V(%d):Delay 1 frame!(%0.3f)\n", sig_is->pictq_size, sig_actual_delay);
#endif
	    goto exit;
    }

    SDL_LockMutex(sig_is->pictq_mutex);
    if (sig_actual_delay< -0.1){
        if (++sig_is->pictq_rindex == sig_is->pictq_size_total)
            sig_is->pictq_rindex = 1;
        sig_is->pictq_size--;
        skip_frame++;
	
	if(sig_actual_delay< -0.5){
		start_queuing=-(sig_actual_delay*100);
	}
#if defined(DEBUG_SYNC)
	printf("A/V(%d):Skip frame!(%0.3f)\n", sig_is->pictq_size, sig_actual_delay);
#endif
	if(sig_is->pictq_size<2)
		goto send_sig;
    }

//printf("sig_actual_delay=%0.3f\n",sig_actual_delay);
    //printf("Display [%d]\n",sig_is->pictq_rindex);

    if (++sig_is->pictq_rindex == sig_is->pictq_size_total)
        sig_is->pictq_rindex = 1;
    sig_is->pictq_size--;

 send_sig:
    SDL_CondSignal(sig_is->pictq_cond);
    SDL_UnlockMutex(sig_is->pictq_mutex);
    ioctl(fbfd,FLCD_SET_FB_NUM,&sig_is->pictq_rindex);

 exit:

    fbn = sig_is->pictq_rindex-1;
    if(fbn==0)
	    fbn = sig_is->pictq_size_total-1;
    /* dequeue the picture */
    vp = &sig_is->pictq[fbn];
    /* update current video pts */
    sig_is->video_current_pts = vp->pts;
    sig_is->video_current_pts_time = av_gettime();
    
    /* compute nominal delay */
    tmp = vp->pts - sig_is->frame_last_pts;
    if (tmp <= 0 || tmp >= 1.0) {
	/* if incorrect delay, use previous one */
	tmp = sig_is->frame_last_delay;
    }
    sig_is->frame_last_delay = tmp;
    sig_is->frame_last_pts = vp->pts;

    sig_actual_delay = vp->pts - get_master_clock(sig_is);
 end:
    fbq_wait=0;
}


void init_time(int framerate)
{ 
  	struct itimerval value; 
  	int ret;

  	value.it_value.tv_sec = 0; 

	if(framerate>0){
		long tmp;
		tmp = 1000000 * HZ / framerate / 1000000;
		tmp = tmp * 1000000 / HZ - 1;
	  	value.it_value.tv_usec = tmp;
	}
  	else{
  		value.it_value.tv_usec = 0;
  		printf("disable timer\n");
	} 
  	value.it_interval = value.it_value; 
  	/*       ITIMER_REAL    decrements in real time, and delivers SIGALRM upon expiration. */
  	ret = setitimer(ITIMER_REAL,&value,NULL); 
	if(ret < 0)
	{
		printf("set timer error\n");
		return;
	}	
    return;	
} 



static void schedule_refresh(VideoState *is, int delay);

static void video_image_display(VideoState *is)
{
#ifdef FFPLAY_SIG_MODE
   	if(sig_is==0)
   	{
   	    int fr;
   	    
   	    skip_frame=0;
   	    sig_is=is;

        fr=is->video_st->codec.frame_rate/is->video_st->codec.frame_rate_base;
        printf("ffplay signal mode, frame rate=%d fps\n",fr);
        init_time(fr);
        ioctl(fbfd,FLCD_SET_FB_NUM,&is->pictq_rindex);
        if(is->pictq_size>0)
        {
            if (++is->pictq_rindex == is->pictq_size_total)
                is->pictq_rindex = 1;
            is->pictq_size--;
        }
   	}
#else
   	ioctl(fbfd,FLCD_SET_FB_NUM,&is->pictq_rindex);
#endif
}

static void delay_video_display(VideoState *is)
{
    if(sig_is==0 && is->video_st && is->pictq_size>3){
	skip_frame=0;
	sig_is=is;

        ioctl(fbfd,FLCD_SET_FB_NUM,&is->pictq_rindex);
    }
    else if(is->video_st){
        if (is->pictq_size <= 1) {
            if (is->end_of_file & NO_PK_IN_VIDEOQ) {
		is->end_of_file |= NO_FRAME_IN_DSPQ;
	    }
	}
    }
}


static inline int compute_mod(int a, int b)
{
    a = a % b;
    if (a >= 0) 
        return a;
    else
        return a + b;
}

static void video_audio_display(VideoState *s)
{
#if 0
    int i, i_start, x, y1, y, ys, delay, n, nb_display_channels;
    int ch, channels, h, h2, bgcolor, fgcolor;
    int16_t time_diff;
    
    /* compute display index : center on currently output samples */
    channels = s->audio_st->codec.channels;
    nb_display_channels = channels;
    if (!s->paused) {
        n = 2 * channels;
        delay = audio_write_get_buf_size(s);
        delay /= n;
        
        /* to be more precise, we take into account the time spent since
           the last buffer computation */
        if (audio_callback_time) {
            time_diff = av_gettime() - audio_callback_time;
            delay += (time_diff * s->audio_st->codec.sample_rate) / 1000000;
        }
        
        delay -= s->width / 2;
        if (delay < s->width)
            delay = s->width;
        i_start = compute_mod(s->sample_array_index - delay * channels, SAMPLE_ARRAY_SIZE);
        s->last_i_start = i_start;
    } else {
        i_start = s->last_i_start;
    }
    bgcolor = SDL_MapRGB(screen->format, 0x00, 0x00, 0x00);
    fill_rectangle(screen,
                   s->xleft, s->ytop, s->width, s->height,
                   bgcolor);

    fgcolor = SDL_MapRGB(screen->format, 0xff, 0xff, 0xff);
    /* total height for one channel */
    h = s->height / nb_display_channels;
    /* graph height / 2 */
    h2 = (h * 9) / 20;
    for(ch = 0;ch < nb_display_channels; ch++) {
        i = i_start + ch;
        y1 = s->ytop + ch * h + (h / 2); /* position of center line */
        for(x = 0; x < s->width; x++) {
            y = (s->sample_array[i] * h2) >> 15;
            if (y < 0) {
                y = -y;
                ys = y1 - y;
            } else {
                ys = y1;
            }
            fill_rectangle(screen,
                           s->xleft + x, ys, 1, y,
                           fgcolor);
            i += channels;
            if (i >= SAMPLE_ARRAY_SIZE)
                i -= SAMPLE_ARRAY_SIZE;
        }
    }

    fgcolor = SDL_MapRGB(screen->format, 0x00, 0x00, 0xff);

    for(ch = 1;ch < nb_display_channels; ch++) {
        y = s->ytop + ch * h;
        fill_rectangle(screen,
                       s->xleft, y, s->width, 1,
                       fgcolor);
    }
    SDL_UpdateRect(screen, s->xleft, s->ytop, s->width, s->height);
#endif
}

/* display the current picture, if any */
static void video_display(VideoState *is)
{
    if (is->audio_st && is->show_audio) 
        video_audio_display(is);
    else if (is->video_st)
        video_image_display(is);
}

static Uint32 sdl_refresh_timer_cb(Uint32 interval, void *opaque)
{
//printf("sdl_refresh_timer_cb\n");
#if 0
    SDL_Event event;
    event.type = FF_REFRESH_EVENT;
    event.user.data1 = opaque;
    SDL_PushEvent(&event);
#endif
    return 0; /* 0 means stop timer */
}

/* schedule a video refresh in 'delay' ms */
static void schedule_refresh(VideoState *is, int delay)
{
    SDL_Delay(delay);
}

/* get the current audio clock value */
static double get_audio_clock(VideoState *is)
{
    double pts;
    int hw_buf_size, bytes_per_sec;
    pts = is->audio_clock;
    hw_buf_size = audio_write_get_buf_size(is);
    bytes_per_sec = 0;
    if (is->audio_st) {
        bytes_per_sec = is->audio_st->codec.sample_rate * 
            2 * is->audio_st->codec.channels;
    }
    if (bytes_per_sec)
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,0))
	    pts = (double)hw_buf_size / bytes_per_sec;
#else
        pts -= (double)hw_buf_size / bytes_per_sec;
#endif
	if (pts < 0)
	   pts = 0;
    return pts;
}

/* get the current video clock value */
static double get_video_clock(VideoState *is)
{
    double delta;
    delta = (av_gettime() - is->video_current_pts_time) / 1000000.0;
    return is->video_current_pts + delta;
}

/* get the current external clock value */
static double get_external_clock(VideoState *is)
{
    int64_t ti;
    ti = av_gettime();
    return is->external_clock + ((ti - is->external_clock_time) * 1e-6);
}

/* get the current master clock value */
static double get_master_clock(VideoState *is)
{
    double val;
    if (is->av_sync_type == AV_SYNC_VIDEO_MASTER && is->video_st)
        val = get_video_clock(is);
    else if (is->av_sync_type == AV_SYNC_AUDIO_MASTER && is->audio_st)
        val = get_audio_clock(is);
    else
        val = get_external_clock(is);
    return val;
}

/* called to display each frame */
static void video_refresh_timer(void *opaque)
{
    VideoState *is = opaque;
    VideoPicture *vp;
    //double actual_delay, delay, sync_threshold, ref_clock, diff;
    double actual_delay, delay;

    if (is->video_st) {
        if (is->pictq_size == 0) {
            if (is->end_of_file & NO_PK_IN_VIDEOQ) {
              is->end_of_file |= NO_FRAME_IN_DSPQ;
			  return;
			}
            /* if no picture, need to wait */
            schedule_refresh(is, 40);
        } else {
#if 0  // Move update video current pts to sig_show() //francis 2007-06-26
            /* dequeue the picture */
            vp = &is->pictq[is->pictq_rindex];
            /* update current video pts */
            is->video_current_pts = vp->pts;
            is->video_current_pts_time = av_gettime();

            /* compute nominal delay */
            delay = vp->pts - is->frame_last_pts;
            if (delay <= 0 || delay >= 1.0) {
                /* if incorrect delay, use previous one */
                delay = is->frame_last_delay;
            }
            is->frame_last_delay = delay;
            is->frame_last_pts = vp->pts;
#endif
#if 0
            /* update delay to follow master synchronisation source */
            if (((is->av_sync_type == AV_SYNC_AUDIO_MASTER && is->audio_st) ||
                 is->av_sync_type == AV_SYNC_EXTERNAL_CLOCK)) {
                /* if video is slave, we try to correct big delays by
                   duplicating or deleting a frame */
                ref_clock = get_master_clock(is);
                diff = vp->pts - ref_clock;
                
                /* skip or repeat frame. We take into account the
                   delay to compute the threshold. I still don't know
                   if it is the best guess */
                sync_threshold = AV_SYNC_THRESHOLD;
                if (delay > sync_threshold)
                    sync_threshold = delay;
                if (fabs(diff) < AV_NOSYNC_THRESHOLD) {
                    if (diff <= -sync_threshold)
                        delay = 0;
                    else if (diff >= sync_threshold)
                        delay = 2 * delay;
                }
            }

            is->frame_timer += delay;
            /* compute the REAL delay (we need to do that to avoid
               long term errors */
            actual_delay = is->frame_timer - (av_gettime() / 1000000.0);
            if (actual_delay < 0.010) {
                /* XXX: should skip picture */
                actual_delay = 0.010;
            }
            schedule_refresh(is, (int)(actual_delay * 1000 + 0.5));
#else
#if 0  // Move calculating A/V delay to sig_show() //francis 2007-06-26
            actual_delay = vp->pts - get_master_clock(is);
            sig_actual_delay=actual_delay;
            if (actual_delay > 0.005) {
            /* launch timer for next picture */
		schedule_refresh(is, (int)(actual_delay * 1000 + 0.5));
            }
#else
            if (sig_actual_delay > AV_SYNC_THRESHOLD && is->pictq_size >2 && (is->audioq.size > MAX_AUDIOQ_SIZE>>1)) {
            /* launch timer for next picture */
		schedule_refresh(is, 30);
            }
#endif
#endif

#if defined(DEBUG_SYNC)
            printf("video: delay=%0.3f actual_delay=%0.3f pts=%0.3f A-V=%f\n",
                   delay, actual_delay, vp->pts, -diff);
#endif
            /* display picture */
            video_display(is);

#ifndef FFPLAY_SIG_MODE
            /* update queue size and signal for next picture */
//            if (++is->pictq_rindex == VIDEO_PICTURE_QUEUE_SIZE)
            if (++is->pictq_rindex == is->pictq_size_total)
//                is->pictq_rindex = 0;
                is->pictq_rindex = 1;
            SDL_LockMutex(is->pictq_mutex);
            is->pictq_size--;
            SDL_CondSignal(is->pictq_cond);
            SDL_UnlockMutex(is->pictq_mutex);
#else
            SDL_LockMutex(is->pictq_mutex);
            SDL_CondSignal(is->pictq_cond);
            SDL_UnlockMutex(is->pictq_mutex);
#endif

        }
    } else if (is->audio_st) {
        /* draw the next audio frame */

        schedule_refresh(is, 40);

        /* if only audio stream, then display the audio bars (better
           than nothing, just to test the implementation */
        
        /* display picture */
        video_display(is);
    } else {
        schedule_refresh(is, 100);
    }
    if (show_status) {
        static int64_t last_time;
        int64_t cur_time;
        int aqsize, vqsize;
        double av_diff;
        
        cur_time = av_gettime();
        if (!last_time || (cur_time - last_time) >= 500 * 1000) {
            aqsize = 0;
            vqsize = 0;
            if (is->audio_st)
                aqsize = is->audioq.size;
            if (is->video_st)
                vqsize = is->videoq.size;
            av_diff = 0;
            if (is->audio_st && is->video_st)
                av_diff = get_audio_clock(is) - get_video_clock(is);
            printf("%7.2f A-V:%7.3f aq=%5dKB vq=%5dKB    \r", 
                   get_master_clock(is), av_diff, aqsize / 1024, vqsize / 1024);
            fflush(stdout);
            last_time = cur_time;
        }
    }
}

#if 0
/* allocate a picture (needs to do that in main thread to avoid
   potential locking problems */
static void alloc_picture(void *opaque)
{
    VideoState *is = opaque;
    VideoPicture *vp;

    vp = &is->pictq[is->pictq_windex];

    if (vp->bmp)
        SDL_FreeYUVOverlay(vp->bmp);

#if 0
    /* XXX: use generic function */
    /* XXX: disable overlay if no hardware acceleration or if RGB format */
    switch(is->video_st->codec.pix_fmt) {
    case PIX_FMT_YUV420P:
    case PIX_FMT_YUV422P:
    case PIX_FMT_YUV444P:
    case PIX_FMT_YUV422:
    case PIX_FMT_YUV410P:
    case PIX_FMT_YUV411P:
        is_yuv = 1;
        break;
    default:
        is_yuv = 0;
        break;
    }
#endif
    vp->bmp = SDL_CreateYUVOverlay(is->video_st->codec.width,
                                   is->video_st->codec.height,
                                   SDL_YV12_OVERLAY,
                                   screen);
    vp->width = is->video_st->codec.width;
    vp->height = is->video_st->codec.height;

    SDL_LockMutex(is->pictq_mutex);
    vp->allocated = 1;
    SDL_CondSignal(is->pictq_cond);
    SDL_UnlockMutex(is->pictq_mutex);
}
#endif
static int queue_picture(VideoState *is, AVFrame *src_frame, double pts)
{
    VideoPicture *vp;
    int dst_pix_fmt;
//    AVPicture pict;

    if ((is->video_st->codec.flags & CODEC_FLAG_PICT_ALLOC_EXTERNAL) == 0) {
	/* wait until we have space to put a new picture */
	SDL_LockMutex(is->pictq_mutex);
	while (is->pictq_size >= is->pictq_size_total &&
	       !is->videoq.abort_request) {
	    SDL_CondWait(is->pictq_cond, is->pictq_mutex);
	}
	SDL_UnlockMutex(is->pictq_mutex);
    }
    if (is->videoq.abort_request)
        return -1;
    vp = &is->pictq[is->pictq_windex];
    if ((is->video_st->codec.flags & CODEC_FLAG_PICT_ALLOC_EXTERNAL) == 0) {
	int width = (is->video_st->codec.width < vp->width)? is->video_st->codec.width: vp->width;
	int height = (is->video_st->codec.height < vp->height)? is->video_st->codec.height: vp->height;
        dst_pix_fmt = PIX_FMT_RGB555;
        img_convert(&vp->pic, dst_pix_fmt, 
                    (AVPicture *)src_frame, is->video_st->codec.pix_fmt, 
                    width, height);
    }
#if 0
    /* alloc or resize hardware picture buffer */
    if (!vp->bmp || 
        vp->width != is->video_st->codec.width ||
        vp->height != is->video_st->codec.height) {
        SDL_Event event;

        vp->allocated = 0;

        /* the allocation must be done in the main thread to avoid
           locking problems */
        event.type = FF_ALLOC_EVENT;
        event.user.data1 = is;
        SDL_PushEvent(&event);
        /* wait until the picture is allocated */
        SDL_LockMutex(is->pictq_mutex);
        while (!vp->allocated && !is->videoq.abort_request) {
            SDL_CondWait(is->pictq_cond, is->pictq_mutex);
        }
        SDL_UnlockMutex(is->pictq_mutex);

        if (is->videoq.abort_request)
            return -1;
    }
    /* if the frame is not skipped, then display it */
    if (vp->bmp)
	{
        /* get a pointer on the bitmap */
        SDL_LockYUVOverlay (vp->bmp);

        dst_pix_fmt = PIX_FMT_YUV420P;
        pict.data[0] = vp->bmp->pixels[0];
        pict.data[1] = vp->bmp->pixels[2];
        pict.data[2] = vp->bmp->pixels[1];

        pict.linesize[0] = vp->bmp->pitches[0];
        pict.linesize[1] = vp->bmp->pitches[2];
        pict.linesize[2] = vp->bmp->pitches[1];
        
        img_convert(&pict, dst_pix_fmt, 
                    (AVPicture *)src_frame, is->video_st->codec.pix_fmt, 
                    is->video_st->codec.width, is->video_st->codec.height);
        /* update the bitmap content */
        SDL_UnlockYUVOverlay(vp->bmp);
    }
#endif
        vp->pts = pts;
        if(is->pictq_size==is->pictq_size_total)    //added by ivan for overflow condiction
            schedule_refresh(is, 1);
        /* now we can update the picture count */
        if (++is->pictq_windex == is->pictq_size_total)
            is->pictq_windex = 1;	// never use index0
        SDL_LockMutex(is->pictq_mutex);
        is->pictq_size++;

        SDL_UnlockMutex(is->pictq_mutex);
	// markd here since check space to put a new picture has already doen before decodeing
    return 0;
}

/* compute the exact PTS for the picture if it is omitted in the stream */
static int output_picture2(VideoState *is, AVFrame *src_frame, double pts1)
{
    double frame_delay, pts;
    pts = pts1;

    /* if B frames are present, and if the current picture is a I
       or P frame, we use the last pts */
    if (is->video_st->codec.has_b_frames && 
        src_frame->pict_type != FF_B_TYPE) {
        /* use last pts */
        pts = is->video_last_P_pts;
        /* get the pts for the next I or P frame if present */
        is->video_last_P_pts = pts1;
    }

    if (pts != 0) {
        /* update video clock with pts, if present */
        is->video_clock = pts;
    } else {
        frame_delay = (double)is->video_st->codec.frame_rate_base /
            (double)is->video_st->codec.frame_rate;
        is->video_clock += frame_delay;
        /* for MPEG2, the frame can be repeated, so we update the
           clock accordingly */
        if (src_frame->repeat_pict) {
            is->video_clock += src_frame->repeat_pict * (frame_delay * 0.5);
        }
    }

#if defined(DEBUG_SYNC) && 0
    {
        int ftype;
        if (src_frame->pict_type == FF_B_TYPE)
            ftype = 'B';
        else if (src_frame->pict_type == FF_I_TYPE)
            ftype = 'I';
        else
            ftype = 'P';
        printf("frame_type=%c clock=%0.3f pts=%0.3f\n", 
               ftype, is->video_clock, pts1);
    }
#endif
    return queue_picture(is, src_frame, is->video_clock);
}

static int video_thread(void *arg)
{
    VideoState *is = arg;
    AVPacket pkt1, *pkt = &pkt1;
    unsigned char *ptr;
    int len, len1, got_picture;
    AVFrame frame;
    int64_t ipts;
    double pts;
    VideoPicture *vp;
    AVCodecContext *pcodec = &is->video_st->codec;

#if 0
    struct sched_param tparam;
    
    tparam.sched_priority = 95;
    sched_setscheduler(getpid(), SCHED_RR, &tparam);
#endif

    if(signal(SIGUSR1,(void *)sig_user)==SIG_ERR)
        printf("user");
    if(signal(SIGALRM,(void *)sig_show)==SIG_ERR)
        printf("signal usr1 error");

//printf("video_thread pid=%d\n",getpid());

    for(;;) {
        while (is->paused && !is->videoq.abort_request) {
            SDL_Delay(10);
        }
//	if (packet_queue_get(&is->videoq, pkt, 1) < 0) {
	if (packet_queue_get_block(&is->videoq, pkt, is->end_of_file) < 0) {
            is->end_of_file |= NO_PK_IN_VIDEOQ;
            break;
	}
	if (pcodec->flags & CODEC_FLAG_PICT_ALLOC_EXTERNAL) {
	    // prepare framebuffer to decode
    	    SDL_LockMutex(is->pictq_mutex);
    	    // get one framebuffer when there are 2 framebuffer available at least
    	    // since one framebuffer must be reserved for hardware play.
    	        	    
	    while (is->pictq_size >= (is->pictq_size_total - 3) &&
           !is->videoq.abort_request) {
           	SDL_CondWait(is->pictq_cond, is->pictq_mutex);
    	    }
 	    
    	    SDL_UnlockMutex(is->pictq_mutex);
    	    vp = &is->pictq[is->pictq_windex];
    	    // pass framebuffer
    	    frame.data[0] = vp->pic.data[0];
    	    frame.data[1] = vp->pic.data[1];
    	    frame.data[2] = vp->pic.data[2];
    	    frame.data_phy[0] = vp->pic.data_phy[0];	//should not be here, ivan
    	    frame.data_phy[1] = vp->pic.data_phy[1];
    	    frame.data_phy[2] = vp->pic.data_phy[2];
	}
        /* NOTE: ipts is the PTS of the _first_ picture beginning in
           this packet, if any */
        ipts = pkt->pts;
        ptr = pkt->data;
        if (pcodec->codec_id == CODEC_ID_RAWVIDEO) {
            avpicture_fill((AVPicture *)&frame, ptr,
                           pcodec->pix_fmt, pcodec->width, pcodec->height);
            pts = 0;
            if (ipts != AV_NOPTS_VALUE)
                pts = (double)ipts * is->ic->pts_num / is->ic->pts_den;
            frame.pict_type = FF_I_TYPE;
            if (output_picture2(is, &frame, pts) < 0)
                goto the_end;
        } else {
            len = pkt->size;
            while (len > 0) {
                if (is->picture_start) {
                    is->ipts = ipts;
                    is->picture_start = 0;
                    ipts = AV_NOPTS_VALUE;
                }
                len1 = avcodec_decode_video(pcodec, &frame, &got_picture, ptr, len);
//printf ("len: 0x%x, 0x%x\n", len, len1);fflush(stdout);
				// ben added start
				if ((len - len1) <= 12) {
				    len = len1;
				}

                if (len1 < 0) //added by ivan
                {
                    printf("Fail to decode\n");
                    len1=len;
                }
                    //break;
                if (got_picture) {
                    pts = 0;
                    if (is->ipts != AV_NOPTS_VALUE)
                        pts = (double)is->ipts * is->ic->pts_num / is->ic->pts_den;
                    if (output_picture2(is, &frame, pts) < 0)
                        goto the_end;
                    is->picture_start = 1;
                }
//printf ("len: 0x%x, 0x%x\n", len, len1);
                ptr += len1;
                len -= len1;
            }
        }
#ifdef ARRAY_NO_MALLOC
	 	repv_put(pkt);
#else
        av_free_packet(pkt);
#endif
    }
 the_end:
    return 0;
}

/* copy samples for viewing in editor window */
static void update_sample_display(VideoState *is, short *samples, int samples_size)
{
    int size, len, channels;

    channels = is->audio_st->codec.channels;

    size = samples_size / sizeof(short);
    while (size > 0) {
        len = SAMPLE_ARRAY_SIZE - is->sample_array_index;
        if (len > size)
            len = size;
        memcpy(is->sample_array + is->sample_array_index, samples, len * sizeof(short));
        samples += len;
        is->sample_array_index += len;
        if (is->sample_array_index >= SAMPLE_ARRAY_SIZE)
            is->sample_array_index = 0;
        size -= len;
    }
}

/* return the new audio buffer size (samples can be added or deleted
   to get better sync if video or external master clock) */
static int synchronize_audio(VideoState *is, short *samples, 
                             int samples_size1, double pts)
{
    int n, samples_size;
    double ref_clock;
    
    n = 2 * is->audio_st->codec.channels;
    samples_size = samples_size1;

    /* if not master, then we try to remove or add samples to correct the clock */
    if (((is->av_sync_type == AV_SYNC_VIDEO_MASTER && is->video_st) ||
         is->av_sync_type == AV_SYNC_EXTERNAL_CLOCK)) {
        double diff, avg_diff;
        int wanted_size, min_size, max_size, nb_samples;
            
        ref_clock = get_master_clock(is);
        diff = get_audio_clock(is) - ref_clock;
        
        if (diff < AV_NOSYNC_THRESHOLD) {
            is->audio_diff_cum = diff + is->audio_diff_avg_coef * is->audio_diff_cum;
            if (is->audio_diff_avg_count < AUDIO_DIFF_AVG_NB) {
                /* not enough measures to have a correct estimate */
                is->audio_diff_avg_count++;
            } else {
                /* estimate the A-V difference */
                avg_diff = is->audio_diff_cum * (1.0 - is->audio_diff_avg_coef);

                if (fabs(avg_diff) >= is->audio_diff_threshold) {
                    wanted_size = samples_size + ((int)(diff * is->audio_st->codec.sample_rate) * n);
                    nb_samples = samples_size / n;
                
                    min_size = ((nb_samples * (100 - SAMPLE_CORRECTION_PERCENT_MAX)) / 100) * n;
                    max_size = ((nb_samples * (100 + SAMPLE_CORRECTION_PERCENT_MAX)) / 100) * n;
                    if (wanted_size < min_size)
                        wanted_size = min_size;
                    else if (wanted_size > max_size)
                        wanted_size = max_size;
                    
                    /* add or remove samples to correction the synchro */
                    if (wanted_size < samples_size) {
                        /* remove samples */
                        samples_size = wanted_size;
                    } else if (wanted_size > samples_size) {
                        uint8_t *samples_end, *q;
                        int nb;
                        
                        /* add samples */
                        nb = (samples_size - wanted_size);
                        samples_end = (uint8_t *)samples + samples_size - n;
                        q = samples_end + n;
                        while (nb > 0) {
                            memcpy(q, samples_end, n);
                            q += n;
                            nb -= n;
                        }
                        samples_size = wanted_size;
                    }
                }
#if 0
                printf("diff=%f adiff=%f sample_diff=%d apts=%0.3f vpts=%0.3f %f\n", 
                       diff, avg_diff, samples_size - samples_size1,
                       is->audio_clock, is->video_clock, is->audio_diff_threshold);
#endif
            }
        } else {
            /* too big difference : may be initial PTS errors, so
               reset A-V filter */
            is->audio_diff_avg_count = 0;
            is->audio_diff_cum = 0;
        }
    }

    return samples_size;
}

/* decode one audio frame and returns its uncompressed size */
static int audio_decode_frame(VideoState *is, uint8_t *audio_buf, double *pts_ptr)
{
    AVPacket *pkt = &is->audio_pkt;
    int len1, data_size;
    double pts;

    for(;;) {
        if (is->paused || is->audioq.abort_request) {
            return -1;
        }
#if 1
        while (is->audio_pkt_size > 0) {
            len1 = avcodec_decode_audio(&is->audio_st->codec,
                                        (int16_t *)audio_buf, &data_size, 
                                        is->audio_pkt_data, is->audio_pkt_size);
            if (len1 < 0)
                break;

            is->audio_pkt_data += len1;
            is->audio_pkt_size -= len1;
            if (data_size > 0) {
                pts = 0;
                if (is->audio_pkt_ipts != AV_NOPTS_VALUE) {
                    pts = (double)is->audio_pkt_ipts * is->ic->pts_num / is->ic->pts_den;
				}
                /* if no pts, then compute it */
                if (pts != 0) {
                    is->audio_clock = pts;
                } else {
                    int n;
                    n = 2 * is->audio_st->codec.channels;
                    is->audio_clock += (double)data_size / (double)(n * is->audio_st->codec.sample_rate);
                }
//printf("aud_dec1: 0x%x 0x%x\n", is->audio_pkt_ipts, AV_NOPTS_VALUE);
//printf("aud_dec2: 0x%x\n", data_size);
#if defined(DEBUG_SYNC)
                {
                    static double last_clock;
                    printf("audio: delay=%0.3f clock=%0.3f pts=%0.3f\n",
                           is->audio_clock - last_clock,
                           is->audio_clock, pts);
                    last_clock = is->audio_clock;
                }
#endif
                *pts_ptr = is->audio_clock;
                is->audio_pkt_ipts = AV_NOPTS_VALUE;
                /* we got samples : we can exit now */
                return data_size;
            }
        }
#endif
       /* free previous packet if any */
#ifdef ARRAY_NO_MALLOC
        if (pkt->destruct)
	 	  repa_put(pkt);
#else
        if (pkt->destruct)
            av_free_packet(pkt);
#endif
        if (is->end_of_file & NO_DATA_IN_FILE)
            is->end_of_file |= NO_PK_IN_AUDIOQ;
        /* read next packet */
        if (packet_queue_get(&is->audioq, pkt, 1) < 0)
            return -1;
        is->audio_pkt_data = pkt->data;
        is->audio_pkt_size = pkt->size;
        is->audio_pkt_ipts = pkt->pts;

        if(start_queuing)
        {
            if(start_queuing<1000)
            {
		  //printf("### Start Queuing %d ms\n",start_queuing);
                fflush(stdout);
                SDL_Delay(start_queuing);
            }
            start_queuing=0;
        }        
    }
}

static int audio_write_get_buf_size(VideoState *is)
{
    unsigned int hw_remain_sz = SDL_GetInputBufSzAudio();
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,0))
    return (hw_remain_sz - is->audio_silence_len);
#else
    return (hw_remain_sz + is->audio_hw_buf_size - is->audio_buf_index);
#endif
}


/* prepare a new audio buffer */
void sdl_audio_callback(void *opaque, Uint8 *stream, int len)
{
    VideoState *is = opaque;
    int audio_size, len1;
    double pts;

    audio_callback_time = av_gettime();

    while (len > 0) {
        if (is->audio_buf_index >= is->audio_buf_size) {
           audio_size = audio_decode_frame(is, is->audio_buf, &pts);
           if (audio_size < 0) {
                /* if error, just output silence */
               is->audio_buf_size = 1024;
               memset(is->audio_buf, 0, is->audio_buf_size);
           } else {
               if (is->show_audio)
                   update_sample_display(is, (int16_t *)is->audio_buf, audio_size);
               audio_size = synchronize_audio(is, (int16_t *)is->audio_buf, audio_size,
                                              pts);
               is->audio_buf_size = audio_size;
           }
           is->audio_buf_index = 0;
        }
        len1 = is->audio_buf_size - is->audio_buf_index;
        if (len1 > len)
            len1 = len;
        memcpy(stream, (uint8_t *)is->audio_buf + is->audio_buf_index, len1);
        len -= len1;
        stream += len1;
        is->audio_buf_index += len1;
	if(audio_size < 0)
		is->audio_silence_len += is->audio_buf_size;
    }
}

/* open a given stream. Return 0 if OK */
static int stream_component_open(VideoState *is, int stream_index)
{
    AVFormatContext *ic = is->ic;
    AVCodecContext *enc;
    AVCodec *codec;
    SDL_AudioSpec wanted_spec, spec;

    if (stream_index < 0 || stream_index >= ic->nb_streams)
        return -1;
    enc = &ic->streams[stream_index]->codec;
    
    /* prepare audio output */
    if (enc->codec_type == CODEC_TYPE_AUDIO) {
        wanted_spec.freq = enc->sample_rate;
        wanted_spec.format = AUDIO_S16SYS;
        /* hack for AC3. XXX: suppress that */
        if (enc->channels > 2)
            enc->channels = 2;
        wanted_spec.channels = enc->channels;
        wanted_spec.silence = 0;
        wanted_spec.samples = SDL_AUDIO_BUFFER_SIZE;
        wanted_spec.callback = sdl_audio_callback;
        wanted_spec.userdata = is;
        if (SDL_OpenAudio(&wanted_spec, &spec) < 0) {
            fprintf(stderr, "SDL_OpenAudio: %s\n", SDL_GetError());
            return -1;
        }
        is->audio_hw_buf_size = spec.size;
	is->audio_silence_len = 0;
    }
	
    codec = avcodec_find_decoder(enc->codec_id);
    if(enc->codec_type == CODEC_TYPE_VIDEO) {
    	// prepare directly decode to framebuffer
    	enc->framebuffer_rgb_stride = is->width;
    	enc->framebuffer_rgb_height = is->height;
    }
    if (!codec ||avcodec_open(enc, codec) < 0)
        return -1;
    switch(enc->codec_type) {
    case CODEC_TYPE_AUDIO:
        is->audio_stream = stream_index;
        is->audio_st = ic->streams[stream_index];
        is->audio_buf_size = 0;
        is->audio_buf_index = 0;
        is->audio_pkt_size = 0;

        /* init averaging filter */
        is->audio_diff_avg_coef = exp(log(0.01) / AUDIO_DIFF_AVG_NB);
        is->audio_diff_avg_count = 0;
        /* since we do not have a precise anough audio fifo fullness,
           we correct audio sync only if larger than this threshold */
        is->audio_diff_threshold = 2.0 * SDL_AUDIO_BUFFER_SIZE / enc->sample_rate;

        memset(&is->audio_pkt, 0, sizeof(is->audio_pkt));
        packet_queue_init(&is->audioq);
		SDL_PauseAudio(0);
        break;
    case CODEC_TYPE_VIDEO:
        is->video_stream = stream_index;
        is->video_st = ic->streams[stream_index];

        is->frame_last_delay = 40e-3;
        is->frame_timer = (double)av_gettime() / 1000000.0;
        is->picture_start = 1;
        is->video_current_pts_time = av_gettime();

        packet_queue_init(&is->videoq);
        is->video_tid = SDL_CreateThread(video_thread, is);
        break;
    default:
        break;
    }
    return 0;
}

static void stream_component_close(VideoState *is, int stream_index)
{
    AVFormatContext *ic = is->ic;
    AVCodecContext *enc;
    
    enc = &ic->streams[stream_index]->codec;

    switch(enc->codec_type) {
    case CODEC_TYPE_AUDIO:
        packet_queue_abort(&is->audioq);
        SDL_CloseAudio();
        packet_queue_end(&is->audioq);
        break;
    case CODEC_TYPE_VIDEO:
        packet_queue_abort(&is->videoq);

        /* note: we also signal this mutex to make sure we deblock the
           video thread in all cases */
        SDL_LockMutex(is->pictq_mutex);
        SDL_CondSignal(is->pictq_cond);
        SDL_UnlockMutex(is->pictq_mutex);

        SDL_WaitThread(is->video_tid, NULL);

        packet_queue_end(&is->videoq);
        // show the original frame
        {
        	int i = 0;
   			ioctl(fbfd,FLCD_SET_FB_NUM,&i);
   		}
        close (fbfd);
        break;
    default:
        break;
    }

    avcodec_close(enc);
    switch(enc->codec_type) {
    case CODEC_TYPE_AUDIO:
        is->audio_st = NULL;
        is->audio_stream = -1;
        break;
    case CODEC_TYPE_VIDEO:
        is->video_st = NULL;
        is->video_stream = -1;
        break;
    default:
        break;
    }
}

void dump_stream_info(AVFormatContext *s)
{
    if (s->track != 0)
        fprintf(stderr, "Track: %d\n", s->track);
    if (s->title[0] != '\0')
        fprintf(stderr, "Title: %s\n", s->title);
    if (s->author[0] != '\0')
        fprintf(stderr, "Author: %s\n", s->author);
    if (s->album[0] != '\0')
        fprintf(stderr, "Album: %s\n", s->album);
    if (s->year != 0)
        fprintf(stderr, "Year: %d\n", s->year);
    if (s->genre[0] != '\0')
        fprintf(stderr, "Genre: %s\n", s->genre);
}

/* since we have only one decoding thread, we can use a global
   variable instead of a thread local variable */
static VideoState *global_video_state;

static int decode_interrupt_cb(void)
{
    return (global_video_state && global_video_state->abort_request);
}

static void set_external_time(VideoState *is)
{
    if (!(is->av_sync_type == AV_SYNC_VIDEO_MASTER && is->video_st) ||
		 !(is->av_sync_type == AV_SYNC_AUDIO_MASTER && is->audio_st))
		 is->external_clock_time = av_gettime();
}
/* this thread gets the stream from the disk or the network */
static int decode_thread(void *arg)
{
    VideoState *is = arg;
    AVFormatContext *ic;
    int err, i, ret, video_index, audio_index;
    AVPacket pkt1, *pkt = &pkt1;
    AVFormatParameters params, *ap = &params;
    VideoPicture * vp, *vpic;
    AVFrame frame;
    AVCodecContext *pcodec = &is->video_st->codec;	

#if 0
    struct sched_param tparam;

    tparam.sched_priority = 90;
    sched_setscheduler(getpid(), SCHED_RR, &tparam);
#endif
//printf("video_thread pid=%d\n",getpid());	
    video_index = -1;
    audio_index = -1;
    is->video_stream = -1;
    is->audio_stream = -1;
    
    global_video_state = is;
    url_set_interrupt_cb(decode_interrupt_cb);

    memset(ap, 0, sizeof(*ap));
    ap->image_format = image_format;
	
    if (   screen_width == 0)	
    	ap->width = is->width;
    else 
	ap->width = screen_width;

    if ( screen_height == 0)	
    	ap->height = is->height;	
    else	
        ap->height = screen_height;	
	
    //printf("decode_thread pid=%d\n",getpid());
    ap->dis_mj = mjpeg_disable;
    if ( mjpeg_disable ) {
		//if (pcodec->flags & CODEC_FLAG_PICT_ALLOC_EXTERNAL) {
			// prepare framebuffer to decode
	 		SDL_LockMutex(is->pictq_mutex);
			// get one framebuffer when there are 2 framebuffer available at least
			// since one framebuffer must be reserved for hardware play.
			while (is->pictq_size >= (is->pictq_size_total - 3) && !is->videoq.abort_request) {
	           		SDL_CondWait(is->pictq_cond, is->pictq_mutex);
			}
			SDL_UnlockMutex(is->pictq_mutex);
			vp = &is->pictq[is->pictq_windex];
    			// pass framebuffer
    			frame.data[0] = vp->pic.data[0];
    			frame.data[1] = vp->pic.data[1];
    			frame.data[2] = vp->pic.data[2];
    			frame.data_phy[0] = vp->pic.data_phy[0];	
    			frame.data_phy[1] = vp->pic.data_phy[1];
    			frame.data_phy[2] = vp->pic.data_phy[2];
			ap->frame = &frame;
		//}
    } 
    	
    err = av_open_input_file(&ic, is->filename, is->iformat, 0, ap);
    if (err < 0) {
        print_error(is->filename, err);
        ret = -1;
        goto fail;
    }
	// haking for static jpeg
	// only run read_header to decode one picture
	// don't run read_packet, it will run decoder again
	if ( mjpeg_disable ) {
		is->pictq_size++;
		ioctl(fbfd,FLCD_SET_FB_NUM,&is->pictq_rindex); // haking FB to show jpeg picture
		goto sj_out;
    }
    is->ic = ic;
    err = av_find_stream_info(ic);
    if (err < 0) {
        fprintf(stderr, "%s: could not find codec parameters\n", is->filename);
        ret = -1;
        goto fail;
    }

    for(i = 0; i < ic->nb_streams; i++) {
        AVCodecContext *enc = &ic->streams[i]->codec;
        switch(enc->codec_type) {
        case CODEC_TYPE_AUDIO:
            if (audio_index < 0 && !audio_disable)
                audio_index = i;
            break;
        case CODEC_TYPE_VIDEO:
            if (video_index < 0 && !video_disable)
                video_index = i;
            break;
        default:
            break;
        }
    }
    if (show_status) {
        dump_format(ic, 0, is->filename, 0);
        dump_stream_info(ic);
    }

    /* open the streams */
    if (audio_index >= 0) {
        stream_component_open(is, audio_index);
    }

	set_external_time(is);
    if (video_index >= 0) {
        stream_component_open(is, video_index);
    } else {
        if (!display_disable)
            is->show_audio = 1;
    }

    if (is->video_stream < 0 && is->audio_stream < 0) {
        fprintf(stderr, "%s: could not open codecs\n", is->filename);
        ret = -1;
        goto fail;
    }

    for(;;) {
        if (is->abort_request)
            break;
#ifdef CONFIG_NETWORK
        if (is->paused != is->last_paused) {
            is->last_paused = is->paused;
            if (ic->iformat == &rtsp_demux) {
                if (is->paused)
                    rtsp_pause(ic);
                else
                    rtsp_resume(ic);
            }
        }
        if (is->paused && ic->iformat == &rtsp_demux) {
            /* wait 10 ms to avoid trying to get another packet */
            /* XXX: horrible */
            SDL_Delay(10);
            continue;
        }
#endif
        /* if the queue are full, no need to read more */
        if (is->audioq.size > MAX_AUDIOQ_SIZE ||
            is->videoq.size > MAX_VIDEOQ_SIZE) {
            /* wait 10 ms */
            SDL_Delay(10);
            continue;
        }

        ret = av_read_packet(ic, pkt);

        if (ret < 0) {
#ifdef CONFIG_NETWORK //ivan
            if(ic->iformat==&rtp_demux)
                continue;
#endif
            is->end_of_file = NO_DATA_IN_FILE;
            break;
        }
        if (pkt->stream_index == is->audio_stream) {
            if (packet_queue_put(&is->audioq, pkt) != 0) {
			   printf ("decode_thread out of memory\n");
			   break;
			}
        } else if (pkt->stream_index == is->video_stream) {
            if (packet_queue_put(&is->videoq, pkt) != 0) {
			   printf ("decode_thread out of memory\n");
			   break;
			}
        } else {
#ifdef ARRAY_NO_MALLOC
            printf ("decode_thread: unused stream %d, pkt = 0x%x\n", pkt->stream_index, (int)pkt);
#else
            av_free_packet(pkt);
#endif
        }
    }
    /* wait until the end */
    while (!is->abort_request) {
        SDL_Delay(100);
    }

sj_out:
    ret = 0;
 fail:
    /* disable interrupting */
    global_video_state = NULL;

    /* close each stream */
    if (is->audio_stream >= 0)
        stream_component_close(is, is->audio_stream);
    if (is->video_stream >= 0)
        stream_component_close(is, is->video_stream);
    if (is->ic) {
        av_close_input_file(is->ic);
        is->ic = NULL; /* safety */
    }
    url_set_interrupt_cb(NULL);

    if (ret != 0) {
            printf("decode_thread\n");
#if 0
        SDL_Event event;

        event.type = FF_QUIT_EVENT;
        event.user.data1 = is;
        SDL_PushEvent(&event);
#endif
    }
    return 0;
}

/* pause or resume the video */
static void stream_pause(VideoState *is)
{
    is->paused = !is->paused;
}

#include <sys/mman.h>
static VideoState *stream_open(const char *filename, AVInputFormat *iformat)
{
    VideoState *is;

    is = av_mallocz(sizeof(VideoState));
    if (!is)
        return NULL;
    pstrcpy(is->filename, sizeof(is->filename), filename);
    is->iformat = iformat;


    is->ytop = 0;
    is->xleft = 0;

    if (!display_disable) {
    	//struct flcd_framebuffer f_data;
    	struct flcd_data f_data;
    	int i;
	VideoPicture * vp;
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,0))
	char fb_dev_name[12];
	char fb_info[32]={0};
	char *fb_info_parse[4]={NULL};

	strcpy(fb_dev_name, "/dev/fb");

	i = open("/proc/fb", O_RDONLY);
	if(i < 0) {
		perror("Open /proc/fb!");
		return NULL;
	}
	if(!read(i, fb_info, 32)) {
		close(i);
		printf("No frame buffer device exist!\n");
		return NULL;
	}
	close(i);

	fb_info_parse[0] = strtok(fb_info, "\n");
	fb_info_parse[2] = strtok(NULL, "\n");

	for(i=0; i<2; i++){
		if(fb_info_parse[i<<1]!=NULL) {
			fb_info_parse[(i<<1)+1] = strchr(fb_info_parse[i<<1], ' ');
			*(fb_info_parse[(i<<1)+1])='\0';
			fb_info_parse[(i<<1)+1]++;
		}
	}

	if(display_dev == LCD){
		for(i=0; i<2; i++)
			if(fb_info_parse[(i<<1)+1]!=NULL && !strcmp(fb_info_parse[(i<<1)+1], "flcd")){
				strcat(fb_dev_name, fb_info_parse[i<<1]);
				printf("Display to LCD\n");
			}
	}
	else if(display_dev == TVE){
		for(i=0; i<2; i++)
			if(fb_info_parse[(i<<1)+1]!=NULL && !strcmp(fb_info_parse[(i<<1)+1], "ftve")) {
				strcat(fb_dev_name, fb_info_parse[i<<1]);
				printf("Display to TVE\n");
			}
	}
	else {
		if(fb_info_parse[1]!=NULL) {
			if(!strcmp(fb_info_parse[1], "flcd"))
				printf("Display to LCD\n");
			else
				printf("Display to TVE\n");
			strcat(fb_dev_name, fb_info_parse[0]);
		}
	}

	// Open the file for reading and writing
	fbfd = open(fb_dev_name, O_RDWR);
#else
	// Open the file for reading and writing
    	fbfd = open("/dev/fb0", O_RDWR);
#endif
	if (!fbfd) {
		printf("LCD Error: cannot open framebuffer device.\n");
		return NULL;
    	}

        {
            int fbn=0; //init to 0
          	if (ioctl(fbfd,FLCD_SET_FB_NUM,&fbn)<0) {
           	    printf("Fail to set fb num\n");
           	    return NULL;
           	}
        }
        
        // Get variable screen information
        if (ioctl(fbfd, FBIOGET_VSCREENINFO, &vinfo)) {
            printf("LCD Error: cannot reading variable information.\n");
			return NULL;
        }

		if (ioctl(fbfd,FLCD_GET_DATA_SEP, &f_data) < 0) {
			printf("LCD Error: can not operate 0x%x\n", FLCD_GET_DATA_SEP);
			return NULL;
		}
		else {
		    unsigned int mmap_addr,mmap_sz;
		    
			if (f_data.frame_no > VIDEO_PICTURE_QUEUE_SIZE_MAX)
				is->pictq_size_total = VIDEO_PICTURE_QUEUE_SIZE_MAX;
			else
				is->pictq_size_total = f_data.frame_no;
			
			mmap_sz=is->pictq_size_total*f_data.buf_len;
			mmap_addr=(unsigned int)mmap(0,mmap_sz,PROT_READ|PROT_WRITE,MAP_SHARED,fbfd, 0);
			if(mmap_addr<0)
			{
			    printf("Fail to mmap flcd frame buffer");
			    return NULL;
			}   
			for (i = 0; i < is->pictq_size_total; i ++) {
				vp = &is->pictq[i];
				vp->pic.linesize[0] = vinfo.xres * 2;	// BPP = 2
                vp->pic.data[0]=(unsigned char *)(mmap_addr+(i*f_data.buf_len));
                vp->pic.data[1]=(unsigned char *)(mmap_addr+(i*f_data.buf_len))+f_data.uv_offset;
                vp->pic.data[2]=(unsigned char *)(mmap_addr+(i*f_data.buf_len))+f_data.uv_offset+(f_data.uv_offset/4);
                vp->pic.data_phy[0] = (unsigned char *)f_data.mp4_map_dma[i]; 	//should not be here, ivan
                vp->pic.data_phy[1] = (unsigned char *)f_data.mp4_map_dma[i]+f_data.uv_offset;
                vp->pic.data_phy[2] = (unsigned char *)f_data.mp4_map_dma[i]+f_data.uv_offset+(f_data.uv_offset/4);
//printf("mmap 0x%x 0x%x 0x%x phy 0x%x 0x%x 0x%x\n",vp->pic.data[0],vp->pic.data[1],vp->pic.data[2],vp->pic.data_phy[0],vp->pic.data_phy[1],vp->pic.data_phy[2]);
//fflush(stdout);
				vp->width = vinfo.xres;
				vp->height = vinfo.yres;
			}
//usleep(10000);
		}
#if 0
		// set display mode YUV
  		i = FLCD_MODE_YCBCR;
		if (ioctl(fbfd, FLCD_SWITCH_MODE,&i) < 0) {
            printf("LCD Error: can not switch to YUV mode\n");
			return NULL;
  		}
#endif
		is->pictq_frame_size = f_data.buf_len;
		is->pictq_rindex = is->pictq_windex = 1;
	//ivan
        is->pictq_size=0;
    	is->width = vinfo.xres;
	is->height = vinfo.yres;
    }
    //printf("==== A width %d height %d ====\n", is->width, is->height);
    
    /* start video display */
    is->pictq_mutex = SDL_CreateMutex();
    is->pictq_cond = SDL_CreateCond();
    /* add the refresh timer to draw the picture */
    schedule_refresh(is, 40);

    is->av_sync_type = av_sync_type;
    is->parse_tid = SDL_CreateThread(decode_thread, is);
    if (!is->parse_tid) {
        av_free(is);
		printf("Can not creat decode thread\n");
        return NULL;
    }
    return is;
}

static void stream_close(VideoState *is)
{
//    VideoPicture *vp;
//    int i;
    /* XXX: use a special url_shutdown call to abort parse cleanly */
    is->abort_request = 1;
    SDL_WaitThread(is->parse_tid, NULL);
#if 0
    /* free all pictures */
    for(i=0;i< is->pictq_size_total; i++) {
        vp = &is->pictq[i];
		iounmap (vp->pic.data[0], is->pictq_frame_size);
    }
#endif
    SDL_DestroyMutex(is->pictq_mutex);
    SDL_DestroyCond(is->pictq_cond);
    av_free (is);
}

void stream_cycle_channel(VideoState *is, int codec_type)
{
    AVFormatContext *ic = is->ic;
    int start_index, stream_index;
    AVStream *st;

    if (codec_type == CODEC_TYPE_VIDEO)
        start_index = is->video_stream;
    else
        start_index = is->audio_stream;
    if (start_index < 0)
        return;
    stream_index = start_index;
    for(;;) {
        if (++stream_index >= is->ic->nb_streams)
            stream_index = 0;
        if (stream_index == start_index)
            return;
        st = ic->streams[stream_index];
        if (st->codec.codec_type == codec_type) {
            /* check that parameters are OK */
            switch(codec_type) {
            case CODEC_TYPE_AUDIO:
                if (st->codec.sample_rate != 0 &&
                    st->codec.channels != 0)
                    goto the_end;
                break;
            case CODEC_TYPE_VIDEO:
                goto the_end;
            default:
                break;
            }
        }
    }
 the_end:
    stream_component_close(is, start_index);
    stream_component_open(is, stream_index);
}



void toggle_pause(void)
{
    if (cur_stream)
        stream_pause(cur_stream);
}

void do_exit(void)
{
    int fbn=0;
    
    do_exit_check=1;   
    init_time(0);
    fbq_wait=0;
    ioctl(fbfd,FLCD_SET_FB_NUM,&fbn);
   
    if (cur_stream) {
        stream_close(cur_stream);
        cur_stream = NULL;
    }
    if (show_status)
        printf("\n");
        
    kill(mainpid,SIGKILL);
}

void toggle_audio_display(void)
{
    if (cur_stream) {
        cur_stream->show_audio = !cur_stream->show_audio;
    }
}

/* read a key without blocking */
static int read_key(void)
{
    int n = 1;
    unsigned char ch;
#ifndef CONFIG_BEOS_NETSERVER
    struct timeval tv;
    fd_set rfds;

    FD_ZERO(&rfds);
    FD_SET(0, &rfds);
    tv.tv_sec = 0;
    tv.tv_usec = 0;
    n = select(1, &rfds, NULL, NULL, &tv);
#endif
#if 0
	return -1;//ivan
#endif
    if (n > 0) {
        n = read(0, &ch, 1);
        if (n == 1)
            return ch;

        return n;
    }
    return -1;
}

static void sig_seg(void)
{
    printf("sig_seg\n");fflush(stdout);
    while(1)
    ;
}
static void sig_int(void)
{
	printf("Ctrl+C to end program\n");
    do_exit();
}
/* handle an event sent by the GUI */
void event_loop(void)
{
#if 1
    int key;
    int fd;
    char pid[20];

    fprintf(stderr, "Press [q] to stop decoding, [space] to pause/resume decoding\n");
    if(signal(SIGINT,(void *)sig_int)==SIG_ERR)
       	printf("signal ctrl+c error\n");
    if(signal(SIGSEGV,(void *)sig_seg)==SIG_ERR)
       	printf("signal SEG error\n");
    //if(signal(SIGUSR1,(void *)sig_show)==SIG_ERR)
    //    printf("signal usr1 error");

    sprintf(pid,"%d",getpid());
    //christie, must write pid, or can't catch the interrupt signal
    //need modified~
#if 0
    if(display_dev)
    {
    	if(display_dev == LCD)
    	{
    	    fd=open("/proc/flcd",O_RDWR);
    	    printf("Display to LCD\n");
    	}
    	else // TVE
    	{
	        fd=open("/proc/ftve",O_RDWR);
	        printf("Display to TV\n");
	    }
    	write(fd,pid,strlen(pid));
    	close(fd);
    }
#endif
    //printf("main loop pid=%d\n",getpid());fflush(stdout);
    
	while (1) {
	    if(do_exit_check)
	        exit(0);	
     /* read_key() returns 0 on EOF */
        key = read_key();
        if (key == 'q'){
           do_exit();
           break;
        }
        if (cur_stream->end_of_file & (NO_PK_IN_AUDIOQ | NO_FRAME_IN_DSPQ)){
	   printf("********** Movie End *************\n");
           do_exit();
           break;
        }
        if (key == ' ')
           toggle_pause();

        schedule_refresh(cur_stream, 20);
       	video_refresh_timer(cur_stream);
 	}
#else
    SDL_Event event;

    for(;;) {
        SDL_WaitEvent(&event);
        switch(event.type) {
        case SDL_KEYDOWN:
            switch(event.key.keysym.sym) {
            case SDLK_ESCAPE:
            case SDLK_q:
                do_exit();
                break;
            case SDLK_p:
            case SDLK_SPACE:
                toggle_pause();
                break;
            case SDLK_a:
                if (cur_stream) 
                    stream_cycle_channel(cur_stream, CODEC_TYPE_AUDIO);
                break;
            case SDLK_v:
                if (cur_stream) 
                    stream_cycle_channel(cur_stream, CODEC_TYPE_VIDEO);
                break;
            case SDLK_w:
                toggle_audio_display();
                break;
            default:
                break;
            }
            break;
        case SDL_VIDEORESIZE:
            if (cur_stream) {
                screen = SDL_SetVideoMode(event.resize.w, event.resize.h, 0, 
                                          SDL_HWSURFACE|SDL_RESIZABLE|SDL_ASYNCBLIT|SDL_HWACCEL);
                cur_stream->width = event.resize.w;
                cur_stream->height = event.resize.h;
            }
            break;
        case SDL_QUIT:
        case FF_QUIT_EVENT:
            do_exit();
            break;
        case FF_ALLOC_EVENT:
//            alloc_picture(event.user.data1);
            break;
        case FF_REFRESH_EVENT:
            video_refresh_timer(event.user.data1);
            break;
        default:
            break;
        }
    }
#endif
}

void opt_width(const char *arg)
{
    screen_width = atoi(arg);
}

void opt_height(const char *arg)
{
    screen_height = atoi(arg);
}

static void opt_format(const char *arg)
{
    file_iformat = av_find_input_format(arg);
    if (!file_iformat) {
        fprintf(stderr, "Unknown input format: %s\n", arg);
        exit(1);
    }
}

static void opt_image_format(const char *arg)
{
    AVImageFormat *f;
    
    for(f = first_image_format; f != NULL; f = f->next) {
        if (!strcmp(arg, f->name))
            break;
    }
    if (!f) {
        fprintf(stderr, "Unknown image format: '%s'\n", arg);
        exit(1);
    }
    image_format = f;
}

#ifdef CONFIG_NETWORK
void opt_rtp_tcp(void)
{
    /* only tcp protocol */
    rtsp_default_protocols = (1 << RTSP_PROTOCOL_RTP_TCP);
}
#endif

void opt_sync(const char *arg)
{
    if (!strcmp(arg, "audio"))
        av_sync_type = AV_SYNC_AUDIO_MASTER;
    else if (!strcmp(arg, "video"))
        av_sync_type = AV_SYNC_VIDEO_MASTER;
    else if (!strcmp(arg, "ext"))
        av_sync_type = AV_SYNC_EXTERNAL_CLOCK;
    else
        show_help();
}

// christie
void opt_display(const char *arg)
{
    if(!strcmp(arg, "lcd"))
    	display_dev = LCD;
    else if(!strcmp(arg, "tve"))
	display_dev = TVE;    
}

const OptionDef options[] = {
    { "h", 0, {(void*)show_help}, "show help" },
    { "x", HAS_ARG, {(void*)opt_width}, "force displayed width", "width" },
    { "y", HAS_ARG, {(void*)opt_height}, "force displayed height", "height" },
#if 0
    /* disabled as SDL/X11 does not support it correctly on application launch */
    { "fs", OPT_BOOL, {(void*)&is_full_screen}, "force full screen" },
#endif
    { "an", OPT_BOOL, {(void*)&audio_disable}, "disable audio" },
    { "ah", HAS_ARG , {(void*)audio_channel_name}, "set audio output channel name", "ch_name" }, 
    { "vn", OPT_BOOL, {(void*)&video_disable}, "disable video" },
    { "nodisp", OPT_BOOL, {(void*)&display_disable}, "disable graphical display" },
    { "f", HAS_ARG, {(void*)opt_format}, "force format", "fmt" },
    { "img", HAS_ARG, {(void*)opt_image_format}, "force image format", "img_fmt" },
    { "stats", OPT_BOOL | OPT_EXPERT, {(void*)&show_status}, "show status", "" },
#ifdef CONFIG_NETWORK
    { "rtp_tcp", OPT_EXPERT, {(void*)&opt_rtp_tcp}, "force RTP/TCP protocol usage", "" },
#endif
    { "sync", HAS_ARG | OPT_EXPERT, {(void*)&opt_sync}, "set audio-video sync. type (type=audio/video/ext)", "type" },
    { "display", HAS_ARG, {(void*)&opt_display}, "set display device (type=lcd/tve)", "type"},
    { "sj", OPT_BOOL, {(void*)&mjpeg_disable}, "disable motion jpeg and static jpeg enable" },
    { NULL, },
};

void show_help(void)
{
    printf("ffplay version " FFMPEG_VERSION ", Copyright (c) 2003 Fabrice Bellard\n"
           "usage: ffplay [options] input_file\n"
           "Simple media player\n");
    printf("\n");
    show_help_options(options, "Main options:\n",
                      OPT_EXPERT, 0);
    show_help_options(options, "\nAdvanced options:\n",
                      OPT_EXPERT, OPT_EXPERT);
    printf("\nWhile playing:\n"
           "q, ESC              quit\n"
           "f                   toggle full screen\n"
           "p, SPC              pause\n"
           "a                   cycle audio channel\n"
           "v                   cycle video channel\n"
           "w                   show audio waves\n"
           );
    exit(1);
}

void parse_arg_file(const char *filename)
{
    if (!strcmp(filename, "-"))
                    filename = "pipe:";
    input_filename = filename;
}



extern int malloc_init(void);

/* Called from the main */
int main(int argc, char **argv)
{
    if (malloc_init() != 0)
      return -1;
    /* register all codecs, demux and protocols */
    av_register_all();

    parse_options(argc, argv, options);

    if (!input_filename)
        show_help();

    if (display_disable) {
        video_disable = 1;
    }

#ifdef ARRAY_NO_MALLOC
    rep_init();
    pack_init(&audio_pack);
    pack_init(&video_pack);
#endif
    cur_stream = stream_open(input_filename, file_iformat);
	if (cur_stream == NULL)
	   return (-1);
//    if (cur_stream->audio_st)
//	  while (SDL_GetAudioStatus() == SDL_AUDIO_STOPPED);
    event_loop();
    return 0;
}
